import os
from functools import wraps

from flask import Flask, request, redirect, url_for, g, render_template

from flask_login import LoginManager, current_user, login_required

from app.config.env import ENV

login_manager = LoginManager()


# login_manager的用户加载器
@login_manager.user_loader
def user_loader(uid):
    from app.model.user import User
    return User.query.get(uid)


# 自定义权限验证装饰器，验证用户权限
def login_required_with_check_scope(func):
    @login_required
    @wraps(func)
    def decorated_view(*args, **kwargs):
        from app.util.scope import inscope
        scope_str = 'AdminScope' if current_user.admin else 'UserScope'
        if not inscope(scope_str, request.endpoint):
            next_ep = 'admin.index_ep' if current_user.admin else 'web.index_ep'
            return redirect(url_for(next_ep))
        return func(*args, **kwargs)

    return decorated_view


def register_blueprint(flask_app):
    from app.web import web
    from app.admin import admin
    flask_app.register_blueprint(admin, url_prefix='/admin')
    flask_app.register_blueprint(web, url_prefix='/web')


def register_plugins(flask_app):
    from app.model.base import db
    db.init_app(flask_app)
    with flask_app.app_context():
        db.create_all()

    login_manager.init_app(flask_app)
    login_manager.login_view = 'login_ep'
    login_manager.login_message = '请先登录'


def configure_app_error_handle(app):
    @app.errorhandler(404)
    def error_404(err):
        return render_template('template/404.html'), 404


def create_app():
    app = Flask(__name__, static_folder='static')

    if ENV == 'dev':
        app.config.from_object('app.config.dev')
    else:
        app.config.from_object('app.config.prod')

    # App实例的文件系统绝对路径，用于上传文件
    app.config.setdefault('APP_INSTANCE_PATH', os.path.abspath(os.path.dirname(app.instance_path)))

    # 注册蓝图模块
    register_blueprint(app)

    # 配置统一的错误处理方法
    configure_app_error_handle(app)

    # 绑定根路径下的路由
    from app.index import bind_app_route
    bind_app_route(app)

    # 注册插件
    register_plugins(app)
    return app
